package com.csproj.basic.service;

import com.csproj.basic.BasicService;
import com.csproj.basic.domain.CollarRecord;
import com.csproj.basic.domain.PDA;
import com.csproj.basic.domain.Site;
import com.csproj.basic.repository.CollarRecordRepository;
import com.csproj.basic.repository.PDARepository;
import com.csproj.basic.repository.SiteRepository;
import com.csproj.basic.service.dto.PDADTO;
import com.csproj.basic.service.mapper.PDAMapper;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.exception.BaseAppException;
import com.csproj.siiat.base.common.util.FileUtils;
import com.csproj.siiat.base.common.util.poi.POIUtil;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.service.UserInfoService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;



import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Service Implementation for managing PDA.
 */
@Service
@Transactional
public class PDAService extends BasicService<PDADTO> {

    private final Logger log = LoggerFactory.getLogger(PDAService.class);

    private final PDARepository pdaRepository;

    private final SiteService siteService;

    private final PDAMapper pDAMapper;

    private final CollarRecordRepository collarRecordRepository;

    private final UserInfoService userInfoService;

    private final SiteRepository siteRepository;


    public PDAService(PDARepository pdaRepository, PDAMapper pDAMapper, SiteService siteService,
                      CollarRecordRepository collarRecordRepository, UserInfoService userInfoService, SiteRepository siteRepository) {
        this.pdaRepository = pdaRepository;
        this.pDAMapper = pDAMapper;
        this.siteService = siteService;
        this.collarRecordRepository = collarRecordRepository;
        this.userInfoService = userInfoService;
        this.siteRepository = siteRepository;
    }

    /**
     * 保存PDA信息并且返回前端需要发的dto，包括扩展属性createName
     *
     * @param pdaDto
     * @return PDADTO
     * TODO 主要负责从前端接收值
     * TODO 其他业务方法，比如保存试卷时同时保存章节
     * TODO DTO的扩展属性，在此方法复制
     */
    public PDADTO saveAndGetDTO(PDADTO pdaDto) {
        PDA pda = pDAMapper.toEntity(pdaDto);
        pda = save(pda);
        pdaDto = pDAMapper.toDto(pda);

        extendSiteName(pdaDto);
        return pdaDto;
    }

    /**
     * 保存PDA信息
     *
     * @param pda
     * @return pda
     * TODO 纯粹的保存方法，通用于所有保存业务调用
     * TODO 赋默认值，保存后，检查数据库，是否所有字段都有准确值
     */
    public PDA save(PDA pda) {

        PDA entity = pdaRepository.findFirstByPdaNoAndDeletedFlagIsFalse(pda.getPdaNo());

        if(StringUtils.isNotBlank(pda.getId())){
            if(entity!=null && !entity.getId().equals(pda.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }else if(entity!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }
        pda.setHasChargingLine(true);
        pda.setEnableFlag(true);
        pda.setCreationTime(ZonedDateTime.now());
        pda.setCreatorUserId(SecurityUtils.getCurrentUserId());
        pda.setLastModificationTime(ZonedDateTime.now());
        pda.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        pda.setDeletedFlag(false);
        return pdaRepository.save(pda);
    }

    /**
     * 获取所有PDA信息
     *
     * @return the list of entities
     */
    public List<PDADTO> findAll() {
        List<PDA> result = pdaRepository.findAll();
        return pDAMapper.toDto(result);
    }

    /**
     * 获取所有PDA信息（分页）
     *
     * @return the list of entities
     * <p>
     * TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    public Page<PDA> findPageList(Map<String, Object> map, Pageable pageable) {
        //根据角色确认查询
        String siteId = userInfoService.getCurrentUserSiteId();
        if(map.get("siteId")==null){
            map.put("siteId",siteId);
        }
        Page<PDA> result = pdaRepository.findPageList(map, pageable);
        return result;
    }

    /**
     * 获取所有PDA信息（分页）
     *
     * @return the list of entities
     * <p>
     * TODO 返回DTO，包含扩展属性
     * TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    public BaseDTO findPageListAndGetDTO(Map<String, Object> map, Pageable pageable) {

        Page<PDA> result = findPageList(map, pageable);
        List<PDADTO> pdaDTOs = pDAMapper.toDto(result.getContent());

        //扩展siteName
        extendSiteName(pdaDTOs);
        setPdaState(pdaDTOs);
        return BaseDTO.createBaseDTO(result).setFieldList(pdaDTOs);
    }

    /**
     * 设计归还状态
     *
     * @param pdadtos
     */
    private void setPdaState(List<PDADTO> pdadtos) {
        pdadtos.forEach(pdadto -> {
            Integer state = getPdaStatusByCollarRecords(pdadto.getId());
            pdadto.setState(state);
        });
    }

    /**
     * 添加为设备state状态
     * <p>
     * 可领用（状态值是1），还是可归还（状态值是2）
     */
    public Integer getPdaStatusByCollarRecords(String pdaId) {
        List<CollarRecord> collarRecords = collarRecordRepository.findByDeviceId(pdaId);
        Integer status = PDADTO.STATE_ENBLED_RECEIVE;
        if (collarRecords.size() > 0) {
            CollarRecord collarRecord = collarRecords.get(0);
            if (collarRecord.getBackDate() == null) {
                status = PDADTO.STATE_ENBLED_BACKE;
            }

        }

        return status;
    }

    /**
     * 根据id，获取PDA信息
     *
     * @param id 主键id
     * @return creator、questionTypeName
     * <p>
     * TODO 返回DTO，包含扩展属性
     * TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    public PDADTO findOneAndGetDTO(String id) {
        PDA pda = findOne(id);
        PDADTO pdaDto = pDAMapper.toDto(pda);

        //扩展siteName
        extendSiteName(pdaDto);
        return pdaDto;
    }

    /**
     * 根据id，获取PDA信息
     *
     * @param id the id of the entity
     * @return the entity
     * <p>
     * TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    public PDA findOne(String id) {
        PDA pda = pdaRepository.findOne(id);
        if (pda == null) {
            throw new BaseAppException(BaseDTO.CODE_PARAM, "id_errors");
        }
        return pda;
    }

    /**
     * 修改机构并且返回前端需要发的dto，包括扩展属性
     *
     * @param pdaDto
     * @return pdaDto
     * TODO 类似SAVE
     */
    public PDADTO updateAndGetDTO(PDADTO pdaDto) {
        PDA pdaForUpdate = pDAMapper.toEntity(pdaDto);
        PDA pda = update(pdaForUpdate);
        PDADTO pdadto = pDAMapper.toDto(pda);

        //扩展siteName
        extendSiteName(pdadto);
        return pdadto;
    }


    /**
     * 根据id，删除PDA信息
     *
     * @param id the id of the entity
     */
    public void delete(String id) {
        PDA pdaDb = findOne(id);
        pdaDb.setDeletedFlag(true);
        pdaDb.setDeletionTime(ZonedDateTime.now());
        pdaDb.setDeleterUserId(SecurityUtils.getCurrentUserId());
        pdaDb = pdaRepository.save(pdaDb);
    }

    /**
     * 修改机构
     *
     * @param pda
     * @return warehouse
     * TODO 类似SAVE
     */
    public PDA update(PDA pda) {
        PDA entity = pdaRepository.findFirstByPdaNoAndDeletedFlagIsFalse(pda.getPdaNo());

        if(StringUtils.isNotBlank(pda.getId())){
            if(entity!=null && !entity.getId().equals(pda.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }else if(entity!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }

        PDA pdaDB = pdaRepository.findOne(pda.getId());
        if (pdaDB == null) {
            throw new BaseAppException(BaseDTO.CODE_PARAM, "id_errors");
        }
        pdaDB.setPdaNo(pda.getPdaNo());
        pdaDB.setHasChargingLine(pda.isHasChargingLine());
        pdaDB.setSiteId(pda.getSiteId());
        pdaDB.setLastModificationTime(ZonedDateTime.now());
        pdaDB.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        pdaDB = pdaRepository.save(pdaDB);
        return pdaDB;
    }

    /**
     * genju
     *
     * @param id the id of the entity
     */
    public PDADTO status(String id, boolean enable) {
        PDA pdaDb = findOne(id);
        pdaDb.setEnableFlag(enable);
        pdaDb.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        pdaDb.setLastModificationTime(ZonedDateTime.now());
        pdaDb = pdaRepository.save(pdaDb);

        PDADTO result = pDAMapper.toDto(pdaDb);
        //扩展siteName
        extendSiteName(result);
        return result;
    }

    /**
     * 设置手持机的使用状态：禁用，启用，默认为启用
     *
     * @param pdadto
     * @return
     */
    public PDADTO updatePdaStatus(PDADTO pdadto) {
        PDA pdaDb = findOne(pdadto.getId());
        pdaDb.setEnableFlag(pdadto.getEnableFlag());
        pdaDb.setReason(pdadto.getReason());
        pdaDb.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        pdaDb.setLastModificationTime(ZonedDateTime.now());
        pdaDb = pdaRepository.save(pdaDb);
        PDADTO result = pDAMapper.toDto(pdaDb);
        return result;
    }

    /**
     * 上传文件
     *
     * @param file
     */
    public String uploadFile(HttpServletRequest request, MultipartFile file) {
        String filePath = FileUtils.excelUpload(request, file, File.separator + "upload" + File.separator + "site");
        return filePath;
    }

    /**
     * 获取统计数量（库存与已归还）
     *
     * @return
     */
    public Map<String, Object> getPdaStatistics() {
        Map<String, Object> map = new HashMap<>();
        List<PDA> stock = pdaRepository.findBySiteIdSotck();
        //未分配
        String siteId = userInfoService.getCurrentUserSiteId();
        int stockNum = stock.size();
        map.put("stock", stockNum);

        if(StringUtils.isNotBlank(siteId)){
            List<PDA> pdas = pdaRepository.findbySiteIdAndEnableFlag(siteId,true);
            map.put("totalCount",pdas.size());
            List<PDA> unBacked = pdaRepository.findByCollarRecordUnBackDateAndSiteIdAAndEnableFlag(CollarRecord.DEVICE_TYPE_ELE,siteId);
            map.put("backed", pdas.size()  - unBacked.size());
        }else{
            //已归还 + 没有分配记录 == 总量-未归还-未分配
            List<PDA> pdas = pdaRepository.findAll();
            List<PDA> unBacked = pdaRepository.findByCollarRecordUnBackDate(CollarRecord.DEVICE_TYPE_ELE);
            map.put("backed", pdas.size() - stockNum - unBacked.size());
            map.put("totalCount",pdas.size());
        }

        String siteName = "";
        if(StringUtils.isNotBlank(siteId)){
            Site site = siteRepository.findById(siteId);
            if(site!=null){
                siteName = site.getSiteName();
            }
        }
        map.put("siteName",siteName);


        return map;
    }

    /**
     * 上传文件
     * @param file
     */
    public BaseDTO  batchImport(MultipartFile file){
        try {
            List<String[]> readResult = POIUtil.readExcel(file);

            if(readResult.size()==0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("upload_faild");
            }
            List<PDA> pdas = new ArrayList<>();
            List<Site> sites = siteRepository.findAll();
            StringBuilder errmsg = new StringBuilder();
            int i = 2;
            for (String[] u : readResult) {
                try {
                    PDA uname = pdaRepository.findFirstByPdaNoAndDeletedFlagIsFalse(u[0]);
                    if(uname!=null){
                        errmsg.append(i-1).append(",");
                    }else{

                        PDA pda = new PDA();
                        i++;
                        pda.setDeletedFlag(false);
                        pda.setEnableFlag(true);
                        pda.setPdaNo(u[0]);
                        pda.setHasChargingLine(true);
                        if(StringUtils.isNotBlank(u[1]))
                        {
                            Site site = sites.stream().filter(s->s.getSiteName().equals(StringUtils.trim(u[1]))).findFirst().orElse(new Site());
                            pda.setSiteId(site.getId());
                        }
                        pdas.add(pda);
                    }

                }catch (Exception e){
                    errmsg.append(i-1).append(",");
                }
            }

            if(pdas.size()>0)
                pdaRepository.save(pdas);
            String msg = "";
            if(errmsg.length()>0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("partial_upload_faild");
            }
        } catch (IOException e) {
            throw new BaseAppException(false,"upload_error");
        }
        return BaseDTO.createBaseDTO().setSuccess(true);
    }
}
